package nachos.threads;

import nachos.machine.*;

/**
 * Coordinates a group of thread queues of the same kind.
 * 
 * @see nachos.threads.ThreadQueue
 */
public abstract class Scheduler {
	/**
	 * Allocate a new scheduler.
	 */
	public Scheduler() {
	}

	/**
	 * Allocate a new thread queue. If <i>transferPriority</i> is <tt>true</tt>,
	 * then threads waiting on the new queue will transfer their "priority" to
	 * the thread that has access to whatever is being guarded by the queue.
	 * This is the mechanism used to partially solve priority inversion.
	 * 
	 * <p>
	 * If there is no definite thread that can be said to have "access" (as in
	 * the case of semaphores and condition variables), this parameter should be
	 * <tt>false</tt>, indicating that no priority should be transferred.
	 * 
	 * <p>
	 * The processor is a special case. There is clearly no purpose to donating
	 * priority to a thread that already has the processor. When the processor
	 * wait queue is created, this parameter should be <tt>false</tt>.
	 * 
	 * <p>
	 * Otherwise, it is beneficial to donate priority. For example, a lock has a
	 * definite owner (the thread that holds the lock), and a lock is always
	 * released by the same thread that acquired it, so it is possible to help a
	 * high priority thread waiting for a lock by donating its priority to the
	 * thread holding the lock. Therefore, a queue for a lock should be created
	 * with this parameter set to <tt>true</tt>.
	 * 
	 * <p>
	 * Similarly, when a thread is asleep in <tt>join()</tt> waiting for the
	 * target thread to finish, the sleeping thread should donate its priority
	 * to the target thread. Therefore, a join queue should be created with this
	 * parameter set to <tt>true</tt>.
	 * 
	 * @param transferPriority
	 *            <tt>true</tt> if the thread that has access should receive
	 *            priority from the threads that are waiting on this queue.
	 * @return a new thread queue.
	 */
	public abstract ThreadQueue newThreadQueue(boolean transferPriority);

	/**
	 * Get the priority of the specified thread. Must be called with interrupts
	 * disabled.
	 * 
	 * @param thread
	 *            the thread to get the priority of.
	 * @return the thread's priority.
	 */
	public int getPriority(KThread thread) {
		Lib.assertTrue(Machine.interrupt().disabled());
		return 0;
	}

	/**
	 * Get the priority of the current thread. Equivalent to
	 * <tt>getPriority(KThread.currentThread())</tt>.
	 * 
	 * @return the current thread's priority.
	 */
	public int getPriority() {
		return getPriority(KThread.currentThread());
	}

	/**
	 * Get the effective priority of the specified thread. Must be called with
	 * interrupts disabled.
	 * 
	 * <p>
	 * The effective priority of a thread is the priority of a thread after
	 * taking into account priority donations.
	 * 
	 * <p>
	 * For a priority scheduler, this is the maximum of the thread's priority
	 * and the priorities of all other threads waiting for the thread through a
	 * lock or a join.
	 * 
	 * <p>
	 * For a lottery scheduler, this is the sum of the thread's tickets and the
	 * tickets of all other threads waiting for the thread through a lock or a
	 * join.
	 * 
	 * @param thread
	 *            the thread to get the effective priority of.
	 * @return the thread's effective priority.
	 */
	public int getEffectivePriority(KThread thread) {
		Lib.assertTrue(Machine.interrupt().disabled());
		return 0;
	}

	/**
	 * Get the effective priority of the current thread. Equivalent to
	 * <tt>getEffectivePriority(KThread.currentThread())</tt>.
	 * 
	 * @return the current thread's priority.
	 */
	public int getEffectivePriority() {
		return getEffectivePriority(KThread.currentThread());
	}

	/**
	 * Set the priority of the specified thread. Must be called with interrupts
	 * disabled.
	 * 
	 * @param thread
	 *            the thread to set the priority of.
	 * @param priority
	 *            the new priority.
	 */
	public void setPriority(KThread thread, int priority) {
		Lib.assertTrue(Machine.interrupt().disabled());
	}

	/**
	 * Set the priority of the current thread. Equivalent to
	 * <tt>setPriority(KThread.currentThread(), priority)</tt>.
	 * 
	 * @param priority
	 *            the new priority.
	 */
	public void setPriority(int priority) {
		setPriority(KThread.currentThread(), priority);
	}

	/**
	 * If possible, raise the priority of the current thread in some
	 * scheduler-dependent way.
	 * 
	 * @return <tt>true</tt> if the scheduler was able to increase the current
	 *         thread's priority.
	 */
	public boolean increasePriority() {
		return false;
	}

	/**
	 * If possible, lower the priority of the current thread user in some
	 * scheduler-dependent way, preferably by the same amount as would a call to
	 * <tt>increasePriority()</tt>.
	 * 
	 * @return <tt>true</tt> if the scheduler was able to decrease the current
	 *         thread's priority.
	 */
	public boolean decreasePriority() {
		return false;
	}
}
